package com.x9space.framework.elastic.util;

import cn.hutool.core.util.ObjectUtil;
import com.x9space.framework.elastic.annotation.QueryBuilderMark;
import com.x9space.framework.elastic.enums.BoolQueryType;
import com.x9space.framework.elastic.handler.QueryHandler;
import com.x9space.framework.elastic.selector.DefaultQueryHandleSelector;
import com.x9space.framework.elastic.selector.QueryHandleSelector;
import org.elasticsearch.index.query.QueryBuilder;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;


public class EsQueryHelper {

    private static QueryHandleSelector selector = new DefaultQueryHandleSelector();

    public static Map<String, List<QueryBuilder>> getPredicate(Object query) {


        // 准备返回集合
        List<QueryBuilder> mustQueryList = new LinkedList<>();
        List<QueryBuilder> shouldQueryList = new LinkedList<>();
        List<QueryBuilder> mustNotQueryList = new LinkedList<>();
        List<QueryBuilder> filterQueryList = new LinkedList<>();

        Map<String, List<QueryBuilder>> resultMap = new HashMap<>();
        resultMap.put("must", mustQueryList);
        resultMap.put("should", shouldQueryList);
        resultMap.put("must_not", mustNotQueryList);
        resultMap.put("filter", filterQueryList);

        if (query == null) return resultMap;

        Class<?> queryClazz = query.getClass();
        // 获取所有字段属性
        List<Field> allQueryFields = new LinkedList<>();
        getAllFields(queryClazz, allQueryFields);

        Annotation[] annotations;
        //遍历每个字段
        for (Field field : allQueryFields) {
            boolean accessible = field.isAccessible();
            try {

                field.setAccessible(true);
                Object o = field.get(query);
                if (ObjectUtil.isNull(o)){
                    continue;
                }
            } catch (IllegalAccessException e) {

            } finally {
                field.setAccessible(accessible);
            }
            // 获取所有注解
            annotations = field.getAnnotations();
            for (Annotation annotation : annotations) {
                // 获取注解类型
                Class<? extends Annotation> annClazz = annotation.annotationType();
                try {
                    QueryBuilderMark mark = annClazz.getAnnotation(QueryBuilderMark.class);
                    if (mark == null) {
                        // 如果没有QueryBuilderMark这种类型注解的标记，那么直接跳过
                        continue;
                    }
                    // 获取里面的查询的类型
                    Method queryType = annClazz.getDeclaredMethod("queryType");
                    BoolQueryType type = (BoolQueryType) queryType.invoke(annotation);
                    // 处理得到 queryBuilder
                    QueryBuilder queryBuilder = handleQuery(annotation, field, query);
                    if (queryBuilder == null) {
                        continue;
                    }
                    switch (type) {
                        case MUST:
                            mustQueryList.add(queryBuilder);
                            break;
                        case MUST_NOT:
                            mustNotQueryList.add(queryBuilder);
                            break;
                        case SHOULD:
                            shouldQueryList.add(queryBuilder);
                            break;
                        case FILTER:
                        default:
                            filterQueryList.add(queryBuilder);
                            break;
                    }
                } catch (IllegalAccessException e) {
                    continue;
                } catch (ClassCastException e) {
                    continue;
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }catch (Exception e) {

                }
            }
        }


        return resultMap;
    }

    private static QueryBuilder handleQuery(Annotation annotation, Field field, Object query) {
        QueryHandler queryHandler = selector.doSelect(annotation);
        if (queryHandler == null) {
            return null;
        }
        return queryHandler.doHandle(annotation, field, query);
    }


    public static List<Field> getAllFields(Class clazz, List<Field> fields) {
        if (clazz != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            getAllFields(clazz.getSuperclass(), fields);
        }
        return fields;
    }
}
